-
Notifications
You must be signed in to change notification settings - Fork 618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(ics29): attempt to refund fees on distribution failure #1245
Conversation
Not sure if this requires more tests to be added. |
modules/apps/29-fee/keeper/escrow.go
Outdated
if err != nil && !bytes.Equal(receiver, refundAccAddress) { | ||
err := k.bankKeeper.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, refundAccAddress, fee) | ||
if err != nil { | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there anything we can do here in the case of both failing? Emit some events?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the goal for emitting the event? Events are mostly just used by relayers I guess.
I think it would be worth logging something to INFO
or DEBUG
logs. Although I haven't seen SDK modules utilizing logging much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the goal for emitting the event?
Just some kind of signalling I guess, was just thinking aloud really. I think logging at WARN
or ERROR
here may be useful, but like you say, most sdk modules don't seem to do much logging.
Feels a little wrong to just silently no-op, that's my only concern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I know what you mean. I guess the problem is that even if we returned an error here we would simply dismiss it at the level above anyway, otherwise, we would err on OnAcknowledgementPacket
which would throw away the ack for the ics20 transfer or w/e as well.
I think we're limited in what we can do here so my vote would be some warn/err logs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a bug if we cannot refund to the original sender? Maybe we should panic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, maybe we should... originally @AdityaSripal had suggested to just no-op in the issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the no-op is for the case that the other fees were distributed fine but this one errors. If we err or panic the other fees won't ever get distributed.
modules/apps/29-fee/keeper/escrow.go
Outdated
|
||
// NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. | ||
ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) | ||
if err != nil && !bytes.Equal(receiver, refundAccAddress) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be worth adding a comment here explaining why this logic is necessary. I find it a bit confusing. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to separate these conditions as well. What happens if there is an err and refundAcc == receiver?
Maybe something like:
if err != nil {
// fee distribution failed, try to refund to original incentivizer
if bytes.Equal(receiver, refundAccAddress) {
return err
}
// attempt to distribute fee to refund address
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a test case for this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's an error and refundAcc == receiver
then sending to the refundAcc has already failed, right?
That's why I combined the conditions using the logical AND.
The issues writes:
If we are trying to refund to original sender and that fails, then we need to just no-op and continue.
In this case, writeFn()
is still called but there would be no state changes to commit (no-op). Do you think this would cause any problems?
I can adapt this tomorrow tho if we feel its better separated.
I'll look at adding a testcase 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests require some refactoring. In progress!
edit: oh man, just realised some of the same refactoring was merged yesterday in #1239
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be on the safe side I think it makes sense to ensure writeFn()
doesn't get called. Otherwise we need to verify that no partial state transitions occurred in x/bank. It might assume state changes are discarded once the error is returned. Nice catch on the refundAcc == receiver
transfer already occurring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'll adapt the logic to represent that. I had similar concerns wrt writeFn()
but wasn't 100%. Thanks :)
// check if the reverse relayer is paid | ||
hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), reverseRelayer, fee.AckFee[0].Add(fee.AckFee[0])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be using HasBalance
as it just ensures it is greater than or equal to.
Updated to be explicit.
Fetch the account balances below, pre fee distribution, then assert the required amounts are added.
}, | ||
}, | ||
// { | ||
// "invalid refund address: no-op, timeout fee remains in escrow", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll see if I can fix this test. Currently failing because we're relying on EscrowPacketFee
and malleate()
is called after this. If we call malleate()
before escrowing the fees, then the RefundAddress
(incentivizer) is the module account, which doesn't have balance.
Bit of a mouth full, but hope it makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The simplest solution is to mutate packetFee.RefundAddress
in malleate()
after the fees are initially escrowed and before DistributePacketFees
is called 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! Thanks for following up on my suggested change
cosmos#1245) <!-- Please read and fill out this form before submitting your PR. Please make sure you have reviewed our contributors guide before submitting your first PR. --> ## Overview Closes: cosmos#1246 <!-- Please provide an explanation of the PR, including the appropriate context, background, goal, and rationale. If there is an issue with this information, please provide a tl;dr and link the issue. --> ## Checklist <!-- Please complete the checklist to ensure that the PR is ready to be reviewed. IMPORTANT: PRs should be left in Draft until the below checklist is completed. --> - [x] New and updated code has appropriate documentation - [x] New and updated code has new and/or updated testing - [x] Required CI checks are passing - [ ] Visual proof for any user facing features like CLI or documentation updates - [x] Linked issues closed with keywords
Description
closes: #862
Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.
docs/
) or specification (x/<module>/spec/
)godoc
comments.Unreleased
section inCHANGELOG.md
Files changed
in the Github PR explorerCodecov Report
in the comment section below once CI passes